#!/usr/bin/env python
#-*- coding: utf-8 -*-
#Using GPL v3
#Author: stuyorks@gmail.com
#Version: 0.1



import urllib2
import re
import sys
import os
import mimetools
import mimetypes
#import optparse
#import getpass

from time import sleep

#domain = "bbs.stu.edu.cn"
#the utmpXXX when login the javeScript will write to Cookie AND
#everyThing we do in BBS need Cookie. So, we must save it with global. 
#utmpnum=""
#utmpkey=""
#utmpuserid=""

#while debug is TRUE, it will record send msg and response msg to 
#the file:./stuBBS.log
#debug=False


class BBS():
    def __init__(self, domain, bbsid, password, debug=False, proxy_info={}):
        self.domain = domain
        self.bbsid = bbsid
        self.password = password
        self.debug = debug
        self.proxy_info = proxy_info

        self.utmpnum=''
        self.utmpkey=''
        self.userid=''

        self.init_proxy()

    def init_proxy(self):
        if self.proxy_info['isProxy']:
            proxy_handler = urllib2.ProxyHandler({"http":"http://%(account)s:%(password)s@%(host)s:%(port)d"% self.proxy_info})
            opener = urllib2.build_opener(proxy_handler)
        else:
            opener = urllib2.build_opener()

        urllib2.install_opener(opener)


    def login(self):
        """
        login function is use the urllib2 module to GET in the BBS.STU.EDU.CN

        return True if login successfull else return False.
        """

        loginHeaders = {
                    'Host':'%s' % self.domain,
                    'User-Agent':'Mozilla/5.0 (X11; U; Linux i686; zh-CN; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5',
                    'Accept':'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
                    'Accept-Language':'zh-cn,zh;q=0.5',
                    'Accept-Encoding':'gzip,deflate',
                    'Accept-Charset':'GB2312,utf-8;q=0.7,*;q=0.7',
                    'Keep-Alive':'300',
                    'Connection':'keep-alive',
                    'Referer':'http://%s/' % self.domain,
                    'Cookie':'utmpnum=; utmpkey=; utmpuserid=; my_t_lines=; my_link_mode=; my_def_mode=; ystat_bc_814849=989653192219184857',
                    'Content-type':'application/x-www-form-urlencoded',
                    }
        loginURL='http://%s/cgi-bin/bbslogin?id=%s&pw=%s' % (self.domain, self.bbsid, self.password)
        debugPrint("login SEND:\n", loginURL+os.linesep+str(loginHeaders),debug=self.debug)

        request = urllib2.Request(url=loginURL,headers=loginHeaders)
        try:
            conn = urllib2.urlopen(request)
        except urllib2.URLError, e:
            print e.reason
            return False
 
        header = str(conn.info())
    
        res = unicode(conn.read(),'gb2312').encode('utf-8')
        debugPrint("login RESPONSE:\n", header+res,debug=self.debug)

        #global utmpnum, utmpkey, utmpuserid
        try:
            self.utmpnum = re.findall(r"document.cookie='utmpnum=(.*)'</script>",res,re.M)[0]
            self.utmpkey = re.findall(r"document.cookie='utmpkey=(.*)'</script>",res,re.M)[0]
            self.utmpuserid = re.findall(r"document.cookie='utmpuserid=(.*)'</script>",res,re.M)[0]
            debugPrint("login GET utmpnum,utmpkey,utmpuserid:\n", self.utmpnum+","+self.utmpkey+","+self.utmpuserid,debug=self.debug)        
        except:
            return False
        return True

    def logout(self):
        """
        logout function is use the urllib2 module to POST DATA to logout.
     
        logoutHeaders: the Cookie segment ystat_bc_...MUST the same with login's!
        """
        logoutHeaders = {
                      'Host':'%s' % self.domain,
                      'User-Agent':'Mozilla/5.0 (X11; U; Linux i686; zh-CN; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5',
                      'Accept':'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
                      'Accept-Language':'zh-cn,zh;q=0.5',
                      'Accept-Encoding':'gzip,deflate',
                      'Accept-Charset':'GB2312,utf-8;q=0.7,*;q=0.7',
                      'Keep-Alive':'300',
                      'Connection':'keep-alive',
                      'Referer':'http://%s/cgi-bin/bbsleft' % self.domain,
                      'Cookie':'utmpnum=%s; utmpkey=%s; utmpuserid=%s; my_t_lines=; my_link_mode=; my_def_mode=; ystat_bc_814849=989653192219184857' % (self.utmpnum, self.utmpkey, self.utmpuserid),
                     } 
        logoutURL = 'http://%s/cgi-bin/bbslogout' % self.domain 
        debugPrint("logout SEND:\n", logoutURL+os.linesep+str(logoutHeaders),debug=self.debug)

        request = urllib2.Request(url=logoutURL,headers=logoutHeaders)
        conn = urllib2.urlopen(request)
        header = str(conn.info())
        res = unicode(conn.read(),'gb2312').encode('utf-8') 
        debugPrint("logout RESPONSE:\n", header+res,debug=self.debug)

    def getMsg(self):
        """
          getMsg function is to use to get Friend Msg from BBS.STU.EDU.CN
          return the page and header.
        """
        getMsgHeaders = {
                      'Host':'%s' % self.domain,
                      'User-Agent':'Mozilla/5.0 (X11; U; Linux i686; zh-CN; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5',
                      'Accept':'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
                      'Accept-Language':'zh-cn,zh;q=0.5',
                      'Accept-Encoding':'gzip,deflate',
                      'Accept-Charset':'GB2312,utf-8;q=0.7,*;q=0.7',
                      'Keep-Alive':'300',
                      'Connection':'keep-alive',
                      #'Referer':'http://%s/cgi-bin/bbsfriend' % domain,
                      'Cookie':'utmpnum=%s; utmpkey=%s; utmpuserid=%s; my_t_lines=; my_link_mode=; my_def_mode=; ystat_bc_814849=989653192219184857' % (self.utmpnum, self.utmpkey, self.utmpuserid),
                      'Cache-Control':'max-age=0',
                    } 
        getMsgURL = 'http://%s/cgi-bin/bbsgetmsg' % self.domain
        debugPrint("getMsg SEND:\n", getMsgURL+os.linesep+str(getMsgHeaders),debug=self.debug)

        request = urllib2.Request(url=getMsgURL,headers=getMsgHeaders)
        conn = urllib2.urlopen(request)
        header = str(conn.info())
        res = unicode(conn.read(),'gb2312').encode('utf-8')
        debugPrint("getMsg RESPONSE:\n", header+res,debug=self.debug)
        return header, res

        
    def getFoot(self):
        """
          getFoot function is to use get BBS.STU.EDU.CN Footer e.g: how many letters?
          return page and header
        """
        footHeaders = {
                      'Host':'%s' % self.domain,
                      'User-Agent':'Mozilla/5.0 (X11; U; Linux i686; zh-CN; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5',
                      'Accept':'text/css,*/*;q=0.1',
                      'Accept-Language':'zh-cn,zh;q=0.5',
                      'Accept-Encoding':'gzip,deflate',
                      'Accept-Charset':'GB2312,utf-8;q=0.7,*;q=0.7',
                      'Keep-Alive':'300',
                      'Connection':'keep-alive',
                      'Referer':'http://%s/cgi-bin/bbsfoot' % self.domain,
                      'Cookie':'utmpnum=%s; utmpkey=%s; utmpuserid=%s; my_t_lines=; my_link_mode=; my_def_mode=; ystat_bc_814849=989653192219184857' % (self.utmpnum, self.utmpkey, self.utmpuserid),
                    } 
        footURL = 'http://%s/cgi-bin/bbsfoot' % self.domain
        debugPrint("bbsGetFoot SEND:\n", footURL+os.linesep+str(footHeaders),debug=self.debug)

        request = urllib2.Request(url=footURL,headers=footHeaders)
        conn = urllib2.urlopen(request)
        header = str(conn.info())
        res = unicode(conn.read(),'gb2312').encode('utf-8') 
        debugPrint("bbsGetFoot RESPONSE:\n", header+res,debug=self.debug)
        return header, res
        
    def postArticle(self, board, title, content):
        """
          postArticle function is to use POST article to BBS.STU.EDU.CN
          return header and page
        """

        postContent = """title=%s&icon=%s&signature=%s&isAttach=0&anonymous=N&exchange=N&text=%s""" % (title, '0', '1',content)+"""%0D%0A"""

        postHeaders = {
             'Host':'%s' % self.domain,
             'User-Agent':'Mozilla/5.0 (X11; U; Linux i686; zh-CN; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5',
             'Accept':'text/html,mage/gif,image/x-xbitmap,image/jpeg,image/pjpeg,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
             'Accept-Language':'zh-cn,zh;q=0.5',
             'Accept-Encoding':'gzip,deflate',
             'Accept-Charset':'GB2312,utf-8;q=0.7,*;q=0.7',
             'Keep-Alive':'300',
             'Connection':'keep-alive',
             'Referer':'http://%s/cgi-bin/bbspst?board=%s' % (self.domain, board), 
             'Cookie':'utmpnum=%s; utmpkey=%s; utmpuserid=%s; my_t_lines=; my_link_mode=; my_def_mode=; ystat_bc_814849=989653192219184857' %
(self.utmpnum, self.utmpkey, self.utmpuserid),
             'Content-type':'application/x-www-form-urlencoded',
             'Content-Length':'%s' % len(postContent),
            }

        postURL = "http://%s/cgi-bin/bbssnd?board=%s" % (self.domain, board)
        debugPrint("postArticle SEND:\n", postURL+os.linesep+str(postHeaders)+os.linesep+postContent,debug=self.debug)

        request = urllib2.Request(url=postURL,headers=postHeaders, data=postContent)
        conn = urllib2.urlopen(request)
        header = str(conn.info())
        res = unicode(conn.read(),'gb2312').encode('utf-8')
        debugPrint("postArticle RESPONSE:\n", header+res,debug=self.debug)
        return header, res


    def uploadPicture(self, picturePath):
        """
        uploadPicture function is to upload a file to BBS.STU.EDU.CN by urllib2 module.
        The arg picturePath is the FULL PATH of the file.
     
        return: True if upload successful else return False
        """
        #fileSize = os.path.getsize(picturePath)
        #print fileSize
        #if 524288 < fileSize:
            #return "bigSize"


        fileObj=open(picturePath,"rb")
        fileContent=fileObj.read()
        fileObj.close()

        #to compare with wirshark package more similarity, I define it is a const..
        #but use mimetools is a good method.
        BOUNDARY = "---------------------------7d91f129901cc"
        #BOUNDARY = mimetools.choose_boundary()
        #print BOUNDARY
    
        fileBaseName = os.path.basename(picturePath)
        #BBS upload file CGI program May use '\' to get FILENAME,
        #So, its format MUST like this: '\yorks.jpg'!
        fileName=r'V:\yorks\%s' % fileBaseName

        CRLF = '\r\n'
        bodyList=[]
        bodyList.extend(
        ['--' + BOUNDARY,
         'Content-Disposition: form-data; name="upload_file"; filename="%s"' % fileName,
         'Content-Type: %s' % mimetypes.guess_type(picturePath)[0],
         '',
         fileContent,
        ])
        bodyList.extend(['--' + BOUNDARY + '--', ''])

        body=CRLF.join(bodyList)

        uploadHeaders = {
                      'Accept':'image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, application/msword, application/vnd.ms-excel, application/vnd.ms-powerpoint, */*',
                      'Referer':'http://%s/cgi-bin/fileupload' % self.domain,
                      'Accept-Language':'zh-cn',
                      'Content-Type':'multipart/form-data; boundary=%s' % BOUNDARY,
                      'Accept-Encoding':'gzip, deflate',
                      'User-Agent':'Mozilla/5.0 (X11; U; Linux i686; zh-CN; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5',
                      'Host': '%s' % self.domain,
                      'Content-Length':'%s' % len(body),
                      'Connection':'Keep-Alive',
                      'Cache-Control':'no-cache',
                      'Cookie':'utmpnum=%s; utmpkey=%s; utmpuserid=%s' % (self.utmpnum, self.utmpkey, self.utmpuserid),
                   }

        uploadURL = "http://%s/cgi-bin/fileupload?job=add" % self.domain 
        debugPrint("uploadPic SEND except BODY:\n", uploadURL+os.linesep+str(uploadHeaders),debug=self.debug)

        request = urllib2.Request(url=uploadURL,headers=uploadHeaders, data=body)
        try:
            conn = urllib2.urlopen(request)
        except urllib2.URLError, e:
            print e.reason
            return False
        header = str(conn.info())
        #res = unicode(conn.read(),'gb2312').encode('utf-8')
        #print fileBaseName.lower()
        res = conn.read()
        debugPrint("uploadPicture RESPONSE:\n", header+res,debug=self.debug)

        if -1 != res.find(fileBaseName.lower()):#uploaded, bbs server rename the filename to lower
            return True
        else:
            return False

    def checkOnline(self, userid):
        """
        checkOnline function is to use to check userid is on line or off line
        return True for on line else return False
        """
        checkOnlineHeaders = {
                      'Host':'%s' % self.domain,
                      'User-Agent':'Mozilla/5.0 (X11; U; Linux i686; zh-CN; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5',
                      'Accept':'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
                      'Accept-Language':'zh-cn,zh;q=0.5',
                      'Accept-Encoding':'gzip,deflate',
                      'Accept-Charset':'GB2312,utf-8;q=0.7,*;q=0.7',
                      'Keep-Alive':'300',
                      'Connection':'keep-alive',
                      'Referer':'http://%s/cgi-bin/bbsfriend' % self.domain,
                      'Cookie':'utmpnum=%s; utmpkey=%s; utmpuserid=%s; my_t_lines=; my_link_mode=; my_def_mode=; ystat_bc_814849=989653192219184857' % (self.utmpnum, self.utmpkey, self.utmpuserid),
                  } 
        checkOnlineURL = 'http://%s/cgi-bin/bbsqry?userid=%s' % (self.domain, userid)
        debugPrint("checkOnline SEND:\n", checkOnlineURL+os.linesep+str(checkOnlineHeaders),debug=self.debug)

        request = urllib2.Request(url=checkOnlineURL,headers=checkOnlineHeaders)
        conn = urllib2.urlopen(request)
        header = str(conn.info())
        res = unicode(conn.read(),'gb2312').encode('utf-8') 
        debugPrint("checkOnline RESPONSE:\n", header+res,debug=self.debug)
    
        if -1 != res.find(u'目前在站上'):
            return True
        else:
            return False

    
    def keepAlive(self):
        #self.getMsg()
        #sleep(60)
        #self.getFoot()
        while True:
            header, page = self.getFoot()
            if -1 != page.lower().find(self.bbsid):
                sleep(300) #5 min
            else:
                return False

def debugPrint(tag, content, filePath="./stuBBS.log", debug=False):
    if debug:
        writeContent=tag+content+os.linesep+"======================================="+os.linesep
        fileObj = open(filePath, 'a')
        fileObj.write(writeContent)
        fileObj.close()
    else:
        pass
       
